using System;
using System.Data;
using System.ComponentModel;
using System.Collections;
#if !NETCFDESIGNTIME
using Microsoft.WindowsCE.Forms;
#endif	

using System.Runtime.InteropServices;

namespace CaptureHButtonsControl
{
	enum KeyModifiers 
	{ 
		None = 0,
		Alt = 1, 
		Control = 2, 
		Shift = 4, 
		Windows = 8,
		Modkeyup = 0x1000,
	}	

	
	/// <summary>
	/// The control captures the hardware buttons and raises events
	/// </summary>
	#if NETCFDESIGNTIME
	[ToolboxItemFilter("System.CF.Windows.Forms", 
	 ToolboxItemFilterType.Custom),
	ToolboxItemFilter("NETCF", ToolboxItemFilterType.Require)]
	#endif

	public sealed class CaptureHButtons:System.ComponentModel.Component
	{		
		#if !NETCFDESIGNTIME
		private HButtonsMessageWindow mWnd;
		private bool disposed=false;
		#endif

		public CaptureHButtons()
		{
			//
			// TODO: Add constructor logic here
			//
			#if !NETCFDESIGNTIME
			mWnd=new HButtonsMessageWindow();	
			mWnd.HotKeyPressed+=new HButtonsMessageWindow.HotKeyPressedEventHandler(mWnd_HotKeyPressed);						
			mWnd.HotKeyUp+=new HButtonsMessageWindow.KeyUpEventHandler(mWnd_KeyUp);
			#endif
		}

		#region Dispose
		~CaptureHButtons()	
		{
			Dispose(false);
		}
		public void Dispose()
		{
			Dispose(true);
			GC.SuppressFinalize(this);
		}

		protected override void Dispose(bool disposing)
		{
			//remove the icon
			#if !NETCFDESIGNTIME
			if(!this.disposed)
			{
				// If disposing equals true, dispose all managed
				// and unmanaged resources.
				if(disposing)
				{
					// Dispose managed resources.
					if (this.mWnd.registered_buttons.Count>0)
						this.UnregisterAll();
					if(this.mWnd.associated_buttons.Count>0)
						this.UnbindAll();
					this.mWnd.registered_buttons.Clear();
					this.mWnd.associated_buttons.Clear();
					this.mWnd.Dispose();
				}
				// Release unmanaged resources. If disposing is false,
				// only the following code is executed.
			}
			// Make sure that resources are not disposed
			// more than once
			disposed = true; 																								
			#endif
			base.Dispose(disposing);
		}

		#endregion

		#if !NETCFDESIGNTIME

		/// <summary>
		/// Find and binds all hardware keys using regitry keys
		/// </summary>		
		public bool FindAndBindAll()
		{	
			bool errors=false;			
			const string keyName = "Software\\Microsoft\\Shell\\Keys";					
			OpenNETCF.Win32.RegistryKey registryKey = OpenNETCF.Win32.Registry.LocalMachine.OpenSubKey(keyName,false);			
			string[] subkeyNames=registryKey.GetSubKeyNames();
			int quar;
			int hard_key;
			for(int i=0;i<registryKey.SubKeyCount;i++)
			{				
				quar=subkeyNames[i].IndexOf("40");
				if (quar!=-1)
				{					
					hard_key=int.Parse(subkeyNames[i].Substring(quar+2,subkeyNames[i].Length-quar-2), System.Globalization.NumberStyles.HexNumber);
					bool ret=SHSetAppKeyWndAssoc(byte.Parse(hard_key.ToString()),this.mWnd.Hwnd);
					if (ret)
					{						
						if (this.mWnd.associated_buttons.BinarySearch(0,this.mWnd.associated_buttons.Count,hard_key,null)<0)
						{
							this.mWnd.associated_buttons.Add(hard_key);
							this.mWnd.associated_buttons.Sort();
						}
					}
					else
						errors=true;
				}												
			}			
			registryKey.Close();									
			return(!errors);	
		}	


		/// <summary>
		/// Find and registers all hardware keys using regitry keys
		/// </summary>		
		public bool FindAndRegisterAll()
		{
			bool errors=false;			
			const string keyName = "Software\\Microsoft\\Shell\\Keys";					
			OpenNETCF.Win32.RegistryKey registryKey = OpenNETCF.Win32.Registry.LocalMachine.OpenSubKey(keyName,false);			
			string[] subkeyNames=registryKey.GetSubKeyNames();
			int quar;
			int hard_key;
			for(int i=0;i<registryKey.SubKeyCount;i++)
			{				
				quar=subkeyNames[i].IndexOf("40");
				if (quar!=-1)
				{					
					hard_key=int.Parse(subkeyNames[i].Substring(quar+2,subkeyNames[i].Length-quar-2), System.Globalization.NumberStyles.HexNumber);
					bool ret=RegisterHotKey(mWnd.Hwnd,hard_key, KeyModifiers.Windows, hard_key);
					if (ret)	
					{
						if (this.mWnd.registered_buttons.BinarySearch(0,this.mWnd.registered_buttons.Count,hard_key,null)<0)
						{
							this.mWnd.registered_buttons.Add(hard_key);
							this.mWnd.registered_buttons.Sort();
						}
					}
					else
						errors=true;						
				}												
			}			
			registryKey.Close();									
			return(!errors);									
		}


		/// <summary>
		/// Unbinds all registered hardware buttons
		/// </summary>		
		public bool UnbindAll()
		{	
			bool errors=false;
			if (this.mWnd.associated_buttons.Count>0)
			{
				for(int i=0;i<this.mWnd.associated_buttons.Count;i++)
				{
					bool ret=SHSetAppKeyWndAssoc(byte.Parse(this.mWnd.associated_buttons[i].ToString()),IntPtr.Zero);
					if (!ret)
						errors=true;
				}
			}
			return(!errors);				
		}


		/// <summary>
		/// Unregisters all registered hardware buttons
		/// </summary>		
		public bool UnregisterAll()
		{											
			bool errors=false;
			if (this.mWnd.registered_buttons.Count>0)
			{
				for(int i=0;i<this.mWnd.registered_buttons.Count;i++)
				{
					bool ret=UnregisterHotKey(mWnd.Hwnd,(int)this.mWnd.registered_buttons[i]);					
					if (!ret)
						errors=true;
				}
			}
			return(!errors);
		}


		
		/// <summary>
		/// Associates a hardware key to the current window		
		/// </summary>
		/// <param name="KeyCode">The code of the hardware button we want to deassociate.</param>
		public bool BindHardwareButton(int KeyCode)
		{								
			bool ret=SHSetAppKeyWndAssoc(byte.Parse(KeyCode.ToString()),this.mWnd.Hwnd);
			if (ret)
			{
				if (this.mWnd.associated_buttons.BinarySearch(0,this.mWnd.associated_buttons.Count,KeyCode,null)<0)
				{
					this.mWnd.associated_buttons.Add(KeyCode);
					this.mWnd.associated_buttons.Sort();
				}
			}
			return(ret);	
		}		


		/// <summary>
		/// Deassociate a hardware key to the current window		
		/// </summary>
		/// <param name="KeyCode">The code of the hardware button we want to deassociate.</param>
		public bool UnbindHardwareButton(int KeyCode)
		{
			int index_obj=this.mWnd.associated_buttons.BinarySearch(0,this.mWnd.associated_buttons.Count,KeyCode,null);
			if (index_obj<0)
				return false;
			else
			{
				bool ret=SHSetAppKeyWndAssoc(byte.Parse(KeyCode.ToString()),IntPtr.Zero);
				if (ret)
				{
					this.mWnd.associated_buttons.RemoveAt(index_obj);				
					this.mWnd.associated_buttons.Sort();
				}
				return ret;
			}			
		}


		/// <summary>
		/// Registers a hardware key to the application		
		/// </summary>
		/// <param name="KeyCode">The code of the hardware button we want to register.</param>
		public bool RegisterHardwareButton(int KeyCode)
		{				
			bool ret=RegisterHotKey(mWnd.Hwnd, KeyCode, KeyModifiers.Windows, KeyCode);
			if (ret)
			{
				if (this.mWnd.registered_buttons.BinarySearch(0,this.mWnd.registered_buttons.Count,KeyCode,null)<0)
				{
					this.mWnd.registered_buttons.Add(KeyCode);
					this.mWnd.registered_buttons.Sort();
				}
			}
			return(ret);					
		}				


		/// <summary>
		/// Unregister hardware key to the application		
		/// </summary>
		/// <param name="KeyCode">The code of the hardware button we want to unregister.</param>		
		public bool UnregisterHardwareButton(int KeyCode)
		{				
			int index_obj=this.mWnd.registered_buttons.BinarySearch(0,this.mWnd.registered_buttons.Count,KeyCode,null);
			if (index_obj<0)
				return false;
			else
			{
				bool ret=UnregisterHotKey(mWnd.Hwnd,KeyCode);
				if (ret)
				{
					this.mWnd.registered_buttons.RemoveAt(index_obj);				
				}
				return ret;
			}										
		}
		#endif


		/// <summary>
		/// HotKeyPressed Event Handler
		/// </summary>
		public delegate void CapturedButtonEventHandler(int KeyCode);		
		/// <summary>
		/// Occurs when a HotKey is pressed
		/// <seealso cref="HotKeyPressed"/>
		/// </summary>
		public event CapturedButtonEventHandler RegisteredButtonPressed;				
		/// <summary>
		/// KeyUp Event Handler
		/// </summary>
		public delegate void KeyUpEventHandler(int KeyCode);		
		/// <summary>
		/// Occurs on WM_KEYUP event
		/// <seealso cref="KeyUp"/>
		/// </summary>
		public event KeyUpEventHandler BindedButtonPressed;

		private void mWnd_HotKeyPressed(int KeyCode)
		{
			if (RegisteredButtonPressed!=null)
			{
				RegisteredButtonPressed(KeyCode);
			}
		}

		private void mWnd_KeyUp(int KeyCode)
		{
			if (BindedButtonPressed!=null)
			{
				BindedButtonPressed(KeyCode);
			}
		}

	
		#if !NETCFDESIGNTIME
		#region P/Invoke		

		[DllImport("aygshell.dll", SetLastError=true)]
		private static extern bool SHSetAppKeyWndAssoc(
			byte bVk,
			IntPtr hWnd // handle to window 			
			); 

		[DllImport("coredll.dll", SetLastError=true)]
		private static extern bool RegisterHotKey(
			IntPtr hWnd, // handle to window 
			int id, // hot key identifier 
			KeyModifiers Modifiers, // key-modifier options 
			int key //virtual-key code 
			); 

		[DllImport("coredll.dll", SetLastError=true)]
		private static extern bool UnregisterHotKey(
			IntPtr hWnd, // handle to window 
			int id // hot key identifier 			
			); 
		#endregion		
		#endif
	}

	#if !NETCFDESIGNTIME	
	public class HButtonsMessageWindow : Microsoft.WindowsCE.Forms.MessageWindow		
	{
		public ArrayList registered_buttons=new ArrayList(5);
		public ArrayList associated_buttons=new ArrayList(5);

		public const int WM_HOTKEY=0x0312;	
		public const int WM_KEYUP=257;
		public HButtonsMessageWindow()
		{			
		}
		protected override void WndProc(ref Message msg)
		{
			//bool handled=false;
			switch(msg.Msg)
			{ 
				case WM_HOTKEY:
					if (HotKeyPressed!=null)
					{														
						if (!(this.registered_buttons.BinarySearch(0,this.registered_buttons.Count,msg.WParam.ToInt32(),null)<0))
						{
							HotKeyPressed(msg.WParam.ToInt32());
			//				handled=true;
						}						
					}
					break;
				case WM_KEYUP:
					if (HotKeyUp!=null)
					{
						if (!(this.associated_buttons.BinarySearch(0,this.associated_buttons.Count,msg.WParam.ToInt32(),null)<0))
						{
							HotKeyUp(msg.WParam.ToInt32());						
			//				handled=true;
						}
					}					
					break;
			} 		
			//if (!handled)
				base.WndProc(ref msg);	
		}

		/// <summary>
		/// HotKeyPressed Event Handler
		/// </summary>
		public delegate void HotKeyPressedEventHandler(int KeyCode);		
		/// <summary>
		/// Occurs when a HotKey is pressed
		/// <seealso cref="HotKeyPressed"/>
		/// </summary>
		public event HotKeyPressedEventHandler HotKeyPressed;

		/// <summary>
		/// KeyUp Event Handler
		/// </summary>
		public delegate void KeyUpEventHandler(int KeyCode);		
		/// <summary>
		/// Occurs on WM_KEYUP event
		/// <seealso cref="KeyUp"/>
		/// </summary>				
		public event KeyUpEventHandler HotKeyUp;		
			
	}
	#endif
}
